package com.cndcare.msc.config;

import com.cndcare.msc.protobuf.CmdEnum;
import com.cndcare.msc.protobuf.MessageVo;
import com.cndcare.msc.service.NettyService;
import com.cndcare.msc.util.SpringBeanFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 虽然@Component默认是单例模式的，但是spring boot 还是会为每个websocket连接初始化一个bean,所以这里使用一个静态的set保存spring boot
 * <p>
 * 创建的bean--MyWebSocket.
 */
@Slf4j
@ServerEndpoint(value = "/websocket/{nickname}")// websocket连接点映射.
@Component
public class MyWebSocket {

    //用来存储每个客户端对应的MyWebSocket对象.
    public static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
    //用来记录sessionId和该session之间的绑定关系.
    public static Map<String, Session> map = new HashMap<String, Session>();

    public Session session;//当前会话的session.

    /**
     * 成功建立连接调用的方法.
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("nickname") String nickname) throws JsonProcessingException {
        this.session = session;
        map.put(session.getId(), session);
        webSocketSet.add(this);//加入set中.
        ObjectMapper objectMapper = new ObjectMapper();
        this.session.getAsyncRemote().sendText(objectMapper.writeValueAsString(
                MessageVo.builder()
                        .cmdEnum(CmdEnum.PUSH_DATA)
                        .data(nickname + "上线了,（我的频道号是" + session.getId() + "）")
                        .build()
        ));
    }

    /**
     * 连接关闭调用的方法.
     */
    @OnClose
    public void onClose(Session session) {
        webSocketSet.remove(this);//从set中移除.
        map.remove(session.getId());
    }

    /**
     * 收到客户端消息后调用的方法.
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("nickname") String nickname) throws IOException {
//        log.info("接收到客户端发来的信息 = {}", message);
        try {
            Session fromUser = MyWebSocket.map.get(session.getId());
            ObjectMapper objectMapper = new ObjectMapper();
            synchronized (fromUser) {
                fromUser.getBasicRemote().sendText(objectMapper.writeValueAsString(
                        MessageVo.builder()
                                .cmdEnum(CmdEnum.PUSH_DATA)
                                .data("收到sessionId【" + session.getId() + "】的心跳包")
                                .build()
                ));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发生错误时调用.
     */
    public void onError(Session session, Throwable error) {
        log.info("发生错误");
        error.printStackTrace();
    }

    /**
     * 群发的方法.
     */
    public void broadcast(MessageVo messageVo) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            StringRedisTemplate stringRedisTemplate = SpringBeanFactory.getBean("stringRedisTemplate", StringRedisTemplate.class);
            stringRedisTemplate.convertAndSend("broadcast", objectMapper.writeValueAsString(messageVo));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 群更新状态.
     */
    public void broadcastStatus() {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            MessageVo messageVo = MessageVo.builder()
                    .cmdEnum(CmdEnum.REFRESH_ALL)
                    .data("刷新所有数据")
                    .build();
            StringRedisTemplate stringRedisTemplate = SpringBeanFactory.getBean("stringRedisTemplate", StringRedisTemplate.class);
            stringRedisTemplate.convertAndSend("broadcast", objectMapper.writeValueAsString(messageVo));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
